<?php

namespace app\common\library;

use addons\epay\library\Service;
use Yansongda\Pay\Pay;
use think\Config;
use think\Log;

class Withdraw
{
    /**
     * 微信商家转账到零钱
     * @param string $account 收款人openid
     * @param float $money 转账金额
     * @param string $desc 转账说明
     * @param string $partner_trade_no 商户订单号（可选）
     * @param string $realName 收款人姓名（可选）
     * @return array
     * @throws \Exception
     */
    public static function wechat($account, $partner_trade_no, $money, $realName, $desc = '提现')
    {
        try {
            $config = Config::get('wechat');
            
            // 转账金额单位转换为分
            $total_fee = intval($money * 100);
            
            // 如果未传入商户订单号，则自动生成
            if (empty($partner_trade_no)) {
                $partner_trade_no = date('YmdHis') . mt_rand(1000, 9999);
            }
            // 请求参数
            $params = [
                'appid' => $config['app_id'],
                'out_bill_no' => $partner_trade_no,
                'transfer_scene_id' => '1005',
                'transfer_remark' => $desc ?: '转账',
                'transfer_amount' => $total_fee,
                'openid' => $account,
                'transfer_scene_report_infos' =>[
                    [
                        'info_type' => '岗位类型',
                        'info_content' => '老师'
                    ],
                    [
                        'info_type' => '报酬说明',
                        'info_content' => '服务费'
                    ]
                ],
                //'user_name' => $realName ? self::encryptUserName($realName) : '',
                'notify_url' => request()->domain() . '/api/notify/withdraw',
            ];
            // 获取签名
            $timestamp = time();
            $nonce = self::createNonceStr();
            $url = 'https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills';
            $method = 'POST';
            $signature = self::generateSignature($method, $url, $timestamp, $nonce, json_encode($params));
            // 请求头
            $headers = [
                'Accept: application/json',
                'User-Agent: yuanqimanman/1.0',
                'Content-Type: application/json',
                'Wechatpay-Serial: ' . $config['serial_no'],
                'Authorization: WECHATPAY2-SHA256-RSA2048 ' . self::getAuthStr($config['mch_id'], $nonce, $timestamp, $signature)
            ];
            // 发送请求
            $ch = curl_init($url);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params));
            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
            $response = curl_exec($ch);
            Log::record('提现申请返回结果：' . $response, 'info');
            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);
            if ($httpCode == 200) {
                $result = json_decode($response, true);
                return [
                    'status' => true,
                    'msg' => '转账申请成功',
                    'payment_no' => $result['transfer_bill_no'],
                    'state'    => 'wait_user_confirm',
                    'package_info'=> $result['package_info']
                ];
            }
            
            return [
                'status' => false,
                'msg' => $error['message'] ?? '转账失败',
                'data' => ''
            ];
            
        } catch (\think\exception\PDOException $e) {
            Log::record('微信转账异常：' . $e->getMessage(), 'error');
            throw new \Exception($e->getMessage());
        }
    }
    
    /**
     * 支付宝提现
     */
    public static function alipay($account, $partner_trade_no, $money, $realName, $desc = '提现')

    {
        $config = Service::getConfig('alipay');
        
        // 使用epay插件的支付功能
        $pay = Pay::alipay($config);
        
        $params = [
            'out_biz_no' => date('YmdHis').rand(1000,9999),
            'trans_amount' => number_format($money, 2, '.', ''),
            'product_code' => 'TRANS_ACCOUNT_NO_PWD',
            'biz_scene' => 'DIRECT_TRANSFER',
            'payee_info' => [
                'identity' => $account,
                'identity_type' => 'ALIPAY_LOGON_ID',
                'name' => $realName
            ],
            'remark' => $desc
        ];
        
        try {
            $result = $pay->transfer($params);
            
            if(isset($result['code']) && $result['code'] === '10000') {
                return [
                    'status' => true,
                    'payment_no' => $result['order_id'],
                    'state'    => 'completed',
                    'package_info'=> ''
                ];
            }
            return [
                'status' => false,
                'msg' => $result['sub_msg'] ?? '支付宝提现失败',
                'data' => $result
            ];
        } catch (\think\exception\PDOException $e) {
            throw new \Exception($e->getMessage());
        }
    }
    
    protected static function createNonceStr($length = 32)
    {
        $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        $str = '';
        for ($i = 0; $i < $length; $i++) {
            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $str;
    }
    
    /**
     * 生成签名
     * @param string $method 请求方法
     * @param string $url 请求地址
     * @param int $timestamp 时间戳
     * @param string $nonce 随机字符串
     * @param string $body 请求体
     * @return string
     */
    private static function generateSignature($method, $url, $timestamp, $nonce, $body)
    {
        $url_parts = parse_url($url);
        $canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?{$url_parts['query']}" : ""));
        
        $message = $method . "\n" .
            $canonical_url . "\n" .
            $timestamp . "\n" .
            $nonce . "\n" .
            $body . "\n";
            
        // 获取商户私钥
        $config = Config::get('wechat');
        $privateKey = file_get_contents(ROOT_PATH . $config['key_path']);
        $privateKey = openssl_get_privatekey($privateKey);
        
        openssl_sign($message, $signature, $privateKey, 'sha256WithRSAEncryption');
        $sign = base64_encode($signature);
        
        openssl_free_key($privateKey);
        
        return $sign;
    }
    
    /**
     * 获取认证字符串
     * @param string $mchId 商户号
     * @param string $nonce 随机字符串
     * @param int $timestamp 时间戳
     * @param string $signature 签名
     * @return string
     */
    private static function getAuthStr($mchId, $nonce, $timestamp, $signature)
    {
        $auth = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
            $mchId, $nonce, $timestamp, Config::get('wechat.serial_no'), $signature);
        return $auth;
    }
    
    /**
     * 加密用户姓名
     * @param string $userName 用户姓名
     * @return string
     */
    private static function encryptUserName($userName)
    {
        $config = Config::get('wechat');
        $publicKey = file_get_contents(ROOT_PATH . $config['cert_path']);
        $encrypted = '';
        openssl_public_encrypt($userName, $encrypted, $publicKey,OPENSSL_PKCS1_OAEP_PADDING);
        return base64_encode($encrypted);
    }
}